using System.Reflection;
using System.Runtime.CompilerServices;

namespace RSCore.Files;

public abstract record class RSFile(string Name)
{
	public string Extension => GetType().Name[..^4];

	public int Length { get; set; }

	public RSDirectory? Parent { get; set; }

	public static RSFile Create(string name, string extension)
	{
		if (factoryCache.TryGetValue(extension, out var factory))
		{
			return factory.Invoke(name);
		}
		var it = from type in Assembly.GetCallingAssembly().GetTypes()
				 where type.IsSubclassOf(typeof(RSFile))
				 where !type.IsAbstract
				 select type;

		RSFile? result = null;
		foreach (var type in it)
		{
			var file = (RSFile)Activator.CreateInstance(type, name)!;
			factoryCache[file.Extension] = name => (RSFile)Activator.CreateInstance(type, name)!;
			if (file.Extension == extension)
			{
				result = file;
			}
		}

		if (result == null)
		{
			throw new Exception($"Cannot find file type for extension {extension}");
		}
		return result;
	}

	public abstract void Deserialize(JsonValue json);

	public abstract void Load(BinaryReader reader);

	public abstract void Save(BinaryWriter writer);

	public abstract void Write(StreamWriter writer, RSFile? annotation = null);

	public abstract void Read(StreamReader reader);

	public abstract JsonValue Serialize();

	private static Dictionary<string, Func<string, RSFile>> factoryCache = new();
}